package core.model
{
import com.adobe.utils.DictionaryUtil;

import core.model.events.PlayerModelEvent;

import flash.errors.IllegalOperationError;
import flash.utils.Dictionary;

import values.avatar.AvatarForce;
import values.avatar.IAvatarValue;
import values.avatar.PlayerAvatarValue;
import values.common.SimplePlayerValue;
import values.events.AvatarValueEvent;
import values.events.InventoryValueEvent;
import values.events.ItemValueEvent;
import values.inventory.InventoryValue;
import values.inventory.InventoryValueList;
import values.inventory.NumbericItemInventoryValue;
import values.inventory.UniqueItemInventoryValue;
import values.item.IItemValue;
import values.item.INumbericItemValue;
import values.item.ItemTemplateValue;
import values.item.ItemTemplateValueList;
import values.item.ItemValue;
import values.item.PackItemTemplateValue;
import values.tech.PlayerTechValue;


[Event(name="levelChanged", type="core.model.events.PlayerModelEvent")]
[Event(name="maxEnergyChanged", type="core.model.events.PlayerModelEvent")]
[Event(name="itemNumChanged", type="core.model.events.PlayerModelEvent")]
[Event(name="addItem", type="core.model.events.PlayerModelEvent")]
[Event(name="removeItem", type="core.model.events.PlayerModelEvent")]

/**
 * ResourceModel
 * @author jliang
 * 
 */
public class PlayerModel extends ModelBase
{
	//==========================================================================
	//  Constructor
	//==========================================================================
	public function PlayerModel()
	{
		super();
	}
	//==========================================================================
	//  Variables
	//==========================================================================
	private var hideInventory:InventoryValue;
	
	private var inventories:Dictionary; /*  InventoryValue */
	//==========================================================================
	//  Properties
	//==========================================================================		
	public function get inventoryList():Array
	{
		var list:Array = DictionaryUtil.getValues(inventories);
		list.sortOn("index", Array.NUMERIC);
		return list;
	}
	
	public function get playerInfo():SimplePlayerValue
	{
		return myForce.player.basicInfo;
	}
	
	public function get playerTechValue():PlayerTechValue
	{
		return myForce.player.playerTechValue;
	}
	
	private var force:AvatarForce;
	
	public function get myForce():AvatarForce
	{
		return force;
	}
	
	public function get myPlayerAvatar():PlayerAvatarValue
	{
		return myForce.player;
	}
	//==========================================================================
	//  Overridden methods: ModelBase
	//==========================================================================
	override public function update(data:*):void
	{				
		
	}
	//==========================================================================
	//  Public methods
	//==========================================================================	
	public function initPlayerInfo(data:Object):void
	{
		//初始化玩家基本信息		
		force = new AvatarForce();
		force.initialize(data.player, data.fight, data.idle);
		
		force.addEventListener(AvatarValueEvent.ADD_EQUIPMENT, avatarEquipmentChangedHandler);
		force.addEventListener(AvatarValueEvent.REMOVE_EQUIPMENT, avatarEquipmentChangedHandler);
		
        hideInventory.items.push(myPlayerAvatar.coinResourceItem);
        addItemListener(myPlayerAvatar.coinResourceItem);
        
        hideInventory.items.push(myPlayerAvatar.cashResourceItem);
        addItemListener(myPlayerAvatar.cashResourceItem);
        
        hideInventory.items.push(myPlayerAvatar.woodResourceItem);
        addItemListener(myPlayerAvatar.woodResourceItem);
        
        hideInventory.items.push(myPlayerAvatar.metalResourceItem);
        addItemListener(myPlayerAvatar.metalResourceItem);
        
        hideInventory.items.push(myPlayerAvatar.energyResourceItem);
        addItemListener(myPlayerAvatar.energyResourceItem);
        
        hideInventory.items.push(myPlayerAvatar.techPointResourceItem);
        addItemListener(myPlayerAvatar.techPointResourceItem);
        
        hideInventory.items.push(myPlayerAvatar.reputationResourceItem);
        addItemListener(myPlayerAvatar.reputationResourceItem);
        
	}
	
	public function initPlayerInventory(data:Object):void
	{
		//初始化背包
		inventories = new Dictionary(true);		
		
		for each (var ivo:InventoryValue in InventoryValueList.inventoryList)
		{
			inventories[ivo.key] = ivo;
			
			ivo.addEventListener(InventoryValueEvent.ADD_ITEM_FAIL, addItemFailHandler);
			ivo.addEventListener(InventoryValueEvent.SPACE_FULL, inventorySpaceFullHandler);
			ivo.addEventListener(InventoryValueEvent.SPACE_EXTENDED, inventorySpaceExtendedHandler);
		}
		
		hideInventory = new NumbericItemInventoryValue();
		hideInventory.maxSpace = -1;
		hideInventory.currentSpace = -1;
		
		//初始化背包里的物品
		/*
		"equipment":[ 
			[ "12FHJ45", "equipment_1", { "level":1 } ] 
		]
		*/
		for each (var idata:Array in data)
		{
			for each (var itemObj:Array in idata)
			{
				var uid:String = itemObj[0] == "" ? null : itemObj[0];
				var template:ItemTemplateValue = ItemTemplateValueList.getByKey(itemObj[1]);
				var params:Object = itemObj[2];
				addItem(ItemValue.create(template, uid,  params));
			}
		}
	}
	
	public function getInventoryValue(key:String):InventoryValue
	{
		return inventories[key];
	}
	
    public function getItemNum(key:String, ...args):Number
    {
		var invt:InventoryValue = getItemInventoryByKey(key);
		
		var num:Number = invt.getItemNum.apply(invt, [ key ].concat(args));
		return num;
    }
	
	public function getNumbericItem(key:String):INumbericItemValue
	{
		var invt:InventoryValue = getItemInventoryByKey(key);
		
		return NumbericItemInventoryValue(invt).getItem(key);
	}
    
    public function getItemNumByTemplateKey(key:String):Number
    {
        var invt:InventoryValue = getItemInventoryByKey(key);
        
        return invt.getItemNumByKey(key);
    }
    
    public function getItemByUID(uid:String, key:String = null):IItemValue
    {
        if (key == null)
        {
            for each (var invt:InventoryValue in inventories)
            {
                if (invt is UniqueItemInventoryValue)
                {
                    var item:IItemValue = invt.getItemByUID(uid);
                    if (item != null) return item;
                }
            }
            return null;
        }
        else
        {
            return getItemInventoryByKey(key).getItemByUID(uid);
        }
    }
    
    public function getItemByData(key:String, params:Object):IItemValue
    {
        return getItemInventoryByKey(key).getItemByData(key, params);
    }
	
    public function hasEnoughNumbericItem(value:INumbericItemValue):Boolean
    {
		return getItemNum(value.key) >= value.num;
    }
	
	public function hasEnoughSpace(value:IItemValue):Boolean
	{
		return getItemInventory(value).hasEnoughSpace(value);
	}
    
    public function addItem(value:IItemValue):*
    {
		var invt:InventoryValue = getItemInventory(value);
		var added:* = invt.addItem(value);
		if (added)
		{
			if (added is IItemValue)
			{
				addItemListener(added);
			}
			else
			{
				for each (var item:IItemValue in added)
				{
					addItemListener(item);
				}
			}
		}		
		
		var evt:PlayerModelEvent = new PlayerModelEvent(PlayerModelEvent.ADD_ITEM);
		evt.params = { items:added, key:value.key };
		this.dispatchEvent(evt);
    }
    
    public function removeItem(value:IItemValue):void
    {		
		var invt:InventoryValue = getItemInventory(value);
		var removed:* = invt.removeItem(value);
		
		if (removed)
		{
			if (removed is IItemValue)
			{
				removeItemListener(removed);
			}
			else
			{
				for each (var item:IItemValue in removed)
				{
					removeItemListener(item);
				}
			}
		}		
		
		var evt:PlayerModelEvent = new PlayerModelEvent(PlayerModelEvent.REMOVE_ITEM);
		evt.params = { items:removed, key:value.key };
		this.dispatchEvent(evt);
    }
    
    /**
     * item.sell(uuid) 
     * @param value
     * 
     */    
    public function sellItem(value:IItemValue):void
    {
        removeItem(value);
        
        execute("item_sell", 
                      [ value.uid ], 
                      sellItemCompleteHander);
    }
    
    protected function sellItemCompleteHander(data:Object):void
    {
        
    }
    
    /**
     * item.open_pack(pack_item_key) 
     * @param value
     * 
     */    
    public function openPack(pack:PackItemTemplateValue):Vector.<IItemValue>
    {
        if (getItemNum(pack.key) <= 0)
        {
            throw IllegalOperationError("openPack method error. There is no pack[ " + pack.key +" ] in the inventory, please check the code.");
        }
        
        removeItem(ItemValue.create(pack, null, { num: 1 }));
        
        var items:Vector.<IItemValue> = pack.generateItems();
        for each (var item:IItemValue in items)
        {
            addItem(item);
        }
        
        execute("item_open_pack", 
                        [ pack.key, ItemValue.convertItemsToObjectArray(items) ], 
                        openPackCompleteHander);
        
        return items;
    }
    
    protected function openPackCompleteHander(data:Object):void
    {
        
    }
    
    /**
     * hero.hire(avatar_key, cost)
     *  
     * @param avatarKey
     * @param cost
     * @param callBack
     * 
     */    
    public function hireHero(avatarKey:String, cost:Object):void
    {
        var hireCompleteHandler:Function = function(data:Object):void
        {
            myForce.hire(avatarKey);
        };
        
        execute("hero_hire", 
                        [ avatarKey, cost ], 
                        hireCompleteHandler);
    }
    
    /**
     *  
     * @param avatarKey
     * 
     */    
    public function abandonHero(avatar:IAvatarValue):void
    {
        var fireCompleteHandler:Function = function(data:Object):void
        {
            myForce.abandon(avatar);
        };
        
        execute("hero_fire", 
                        [ avatar.key ], 
                        fireCompleteHandler);
    }
	//==========================================================================
	//  Private methods
	//==========================================================================
	private function addItemListener(item:IItemValue):void
	{
		item.addEventListener(ItemValueEvent.NUM_CHANGED, numbericItemNumChangedHandler);
	}
	
	private function removeItemListener(item:IItemValue):void
	{
		item.removeEventListener(ItemValueEvent.NUM_CHANGED, numbericItemNumChangedHandler);
	}
	
	private function getItemInventory(value:IItemValue):InventoryValue
	{
		if (value.template.showInInventory)
		{
			return inventories[value.template.inventory];
		}
		else
		{
			return hideInventory;
		}
	}
	
	private function getItemInventoryByKey(key:String):InventoryValue
	{
		var template:ItemTemplateValue = ItemTemplateValueList.getByKey(key);
		if (template.showInInventory)
		{
			return inventories[template.inventory];
		}
		else
		{
			return hideInventory;
		}
	}
    //==========================================================================
    //  Event handlers
    //==========================================================================    	
	private function numbericItemNumChangedHandler(event:ItemValueEvent):void
	{
		var item:INumbericItemValue = event.params.value;
		
        var isResource:Boolean = (item.template.type == "resource");
        
		var evt:PlayerModelEvent = new PlayerModelEvent(PlayerModelEvent.ITEM_NUM_CHANGED);
		evt.params = { itemKey:item.key, num:getItemNum(item.key), isResource: isResource };
		this.dispatchEvent(evt);
	}
	
	private function addItemFailHandler(event:InventoryValueEvent):void
	{
		trace("Add item fail. " + event.params.inventory.key);
	}
	
	private function inventorySpaceFullHandler(event:InventoryValueEvent):void
	{
		trace("Space full. " + event.params.inventory.key);
	}
	
	private function inventorySpaceExtendedHandler(event:InventoryValueEvent):void
	{
		trace("Space extended. " + event.params.inventory.key);
	}
	
	private function avatarEquipmentChangedHandler(event:AvatarValueEvent):void
	{
		var avatar:IAvatarValue = event.params.avatar;
		var item:IItemValue = event.params.equipment;
		
		if (event.type == AvatarValueEvent.ADD_EQUIPMENT)
		{
			removeItem(item);
		}
		else if (event.type == AvatarValueEvent.REMOVE_EQUIPMENT)
		{
			addItem(item);
		}
	}
}
}




